import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class GameJPanel extends JPanel implements KeyListener, Runnable {
    private int t = 0, z = 5, x, y, t1 = 0, t2 = 0, t3 = 0, x1, y1, dir, x2, y2, fh = 0, js = 0, sw = 0;
    MyTank myTank = null;
    Vector<EnemyTank> enemyTanks = new Vector<>();
    GameJPanel(){
        myTank = new MyTank((int)(Math.random() * 1200), (int)(Math.random() * 700));
    }
    @Override
    public void paint(Graphics g){
        if(!myTank.isLife() && fh < 1){
            myTank.setLife(true);
            myTank.setX((int)(Math.random() * 1200));
            myTank.setY((int)(Math.random() * 700));
            myTank.setDir((int)(Math.random() * 4));
        }
        while(enemyTanks.size() < 10 && z > 0){
            z --;
            EnemyTank enemy = new EnemyTank((int)(Math.random() * 1270), (int)(Math.random() * 770));
            enemy.setDir((int)(Math.random() * 4));
            enemyTanks.add(enemy);
            Thread thread = new Thread(enemy);
            thread.start();
        }
        // 使用父类的paint方法，进行初始化
        super.paint(g);
        // 设置背景板大小
        g.fillRect(0, 0, 1300, 800);
        Font font=new Font("宋体",Font.BOLD , 25);
        g.setFont(font);
        g.drawString("累计击杀：" + js,1320, 40);
        g.drawString("累计死亡：" + sw,1320, 80);
        if(t3 > 0){
            g.setColor(Color.red);
            switch (dir){
                case 0:
                case 2:
                    for(int i = Math.min(y1, y2) ; i < Math.max(y1, y2) ; i ++){
                        if(i % 2 < 1){
                            g.fill3DRect(Math.min(x1, x2), i, Math.max(x1, x2) - Math.min(x1, x2), 1, false);
                        }else{
                            g.fill3DRect(Math.min(x1, x2), i, 1, 1, false);
                            g.fill3DRect(Math.max(x1, x2) - 1, i, 1, 1, false);
                        }
                    }
                    break;
                default:
                    for(int i = Math.min(x1, x2) ; i < Math.max(x1, x2) ; i ++){
                        if(i % 2 < 1){
                            g.fill3DRect(i, Math.min(y1, y2), 1, Math.max(y1, y2) - Math.min(y1, y2), false);
                        }else{
                            g.fill3DRect(i, Math.min(y1, y2), 1, 1, false);
                            g.fill3DRect(i, Math.max(y1, y2) - 1, 1, 1, false);
                        }
                    }
            }
        }
        if(myTank.isLife()){
            g.setColor(Color.white);
            for(int i = 0; i < myTank.vector.size(); i ++){
                Bullet bullet = myTank.vector.get(i);
                if(bullet.isLife()) {
                    g.fillOval(bullet.getX() - 4, bullet.getY() - 4, 9, 9);
                }else{
                    myTank.vector.remove(bullet);
                }
            }
            drawTank(myTank.getX(), myTank.getY(), g, myTank.getDir(), myTank.getType());
        }
        for(int j = 0; j < enemyTanks.size(); j ++) {
            EnemyTank enemy = enemyTanks.get(j);
            if(enemy.isLife()){
                drawTank(enemy.getX(), enemy.getY(), g, enemy.getDir(), enemy.getType());
            }else {
                for(int i = 0 ; i < enemy.vector.size() ; i ++){
                    enemy.vector.remove(i);
                }
                enemyTanks.remove(j);
                continue;
            }
            for(int i = 0 ; i < enemy.vector.size() ; i ++){
                Bullet bullet = enemy.vector.get(i);
                if(bullet.isLife()){
                    g.fillOval(bullet.getX() - 4, bullet.getY() - 4, 9, 9);
                }else{
                    enemy.vector.remove(bullet);
                }
            }
        }
    }
    public void drawTank(int x, int y, Graphics g, int dir, int type){
        if(type < 1) g.setColor(Color.PINK);
        else if(type < 2) g.setColor(Color.YELLOW);
        switch (dir){
            // 朝上
            case 0:
                g.fill3DRect(x, y, 7, 45, false );
                g.fill3DRect(x + 7, y + 3, 16, 40, false );
                g.fill3DRect(x + 23, y, 7, 45, false );
                for(int i = 11; i < 20; i ++){
                    g.drawLine(x + i, y + (i < 13 || i > 17 ? -5 : 15), x + i, y - 10);
                }
                g.fillOval(x + 2, y + 10, 26, 26 );
                break;
            // 朝左
            case 1:
                g.fill3DRect(x, y, 45, 7, false);
                g.fill3DRect(x + 3, y + 7, 40, 16 ,false);
                g.fill3DRect(x, y + 23, 45, 7, false);
                for(int i = 11; i < 20; i ++){
                    g.drawLine( x + (i < 13 || i > 17 ? -5 : 15), y + i, x - 10, y + i);
                }
                g.fillOval( x + 10, y + 2, 26, 26);
                break;
            // 朝下
            case 2:
                g.fill3DRect(x, y, 7, 45, false );
                g.fill3DRect(x + 7, y + 2, 16, 40, false );
                g.fill3DRect(x + 23, y, 7, 45, false );
                for(int i = 11; i < 20; i ++){
                    g.drawLine(x + i, y + (i < 13 || i > 17 ? 50 : 30), x + i, y + 55);
                }
                g.fillOval(x + 2, y + 9, 26, 26 );
                break;
            // 朝右
            case 3:
                g.fill3DRect(x, y, 45, 7, false );
                g.fill3DRect(x + 2, y + 7, 40, 16, false );
                g.fill3DRect(x, y + 23, 45, 7, false );
                for(int i = 11; i < 20; i ++){
                    g.drawLine(x + (i < 13 || i > 17 ? 50 : 30), y + i, x + 55, y + i);
                }
                g.fillOval(x + 9, y + 2, 26, 26 );
                break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(!myTank.isLife()) return;
        if(t1 > 0) return;
        if(e.getKeyCode() == KeyEvent.VK_W || e.getKeyCode() == KeyEvent.VK_UP) {
            myTank.setDir(0);
            myTank.up();
        }else if(e.getKeyCode() == KeyEvent.VK_A || e.getKeyCode() == KeyEvent.VK_LEFT){
            myTank.setDir(1);
            myTank.left();
        }else if(e.getKeyCode() == KeyEvent.VK_S || e.getKeyCode() == KeyEvent.VK_DOWN){
            myTank.setDir(2);
            myTank.down();
        }else if(e.getKeyCode() == KeyEvent.VK_D || e.getKeyCode() == KeyEvent.VK_RIGHT){
            myTank.setDir(3);
            myTank.right();
        }
        if(myTank.isLife() && e.getKeyCode() == KeyEvent.VK_J || e.getKeyCode() == KeyEvent.VK_SPACE) {
            myTank.attack();
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        if(!myTank.isLife()) return;
        if(e.getKeyCode() == KeyEvent.VK_F){
            if(t2 > 0){
                t1 = t2 = 0;
                myTank.setX(x);
                myTank.setY(y);
                myTank.setSpeed(6);
            }else if(t3 < 1){
                t3 = 200;
                t2 = 100;
                t1 = 10;
                x2 = x = myTank.getX();
                y2 = y = myTank.getY();
                dir = myTank.getDir();
                switch (dir){
                    case 0:
                        x2 += 30;
                        y2 += 45;
                        break;
                    case 1:
                        x2 += 45;
                        y2 += 30;
                        break;
                    case 3:
                        y2 += 30;
                        break;
                }
            }
        }
    }

    @Override
    public void run(){
        while(true){
            if(t == 200){
                t = 0;
                z ++;
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if(t1 > 0){
                t1 --;
                myTank.setSpeed(200);
                switch (myTank.getDir()){
                    case 0:
                        myTank.up();
                        break;
                    case 1:
                        myTank.left();
                        break;
                    case 2:
                        myTank.down();
                        break;
                    default:
                        myTank.right();
                }
                x1 = myTank.getX();
                y1 = myTank.getY();
                switch (dir){
                    case 2:
                        x1 += 30;
                        y1 += 45;
                        break;
                    case 3:
                        x1 += 45;
                        break;
                }
                if(t1 < 1) myTank.setSpeed(6);
            }
            t2 = Math.max(t2 - 1, 0);
            t3 = Math.max(t3 - 1, 0);
            fh = Math.max(fh - 1, 0);
            t ++;
            for(Bullet bullet : myTank.vector){
                if(check(bullet)){
                    js ++;
                }
            }
            boolean p = false;
            for(EnemyTank tank : enemyTanks){
                if(checkT(tank)){
                    js ++;
                    continue;
                }
                for(int i = 0 ; i < tank.vector.size() ; i ++){
                    check(tank.vector.get(i));
                    /*if(check(tank.vector.get(i))){
                        p = true;
                        break;
                    }*/
                }
//                if(p) break;
            }
//            if(p) break;
            repaint();
        }
    }

    public boolean check(Bullet bullet){
        if(bullet.getX() < 0 || bullet.getX() > 1300 || bullet.getY() < 0 || bullet.getY() > 800){
            bullet.setLife(false);
            return false;
        }
        if(t1 > 0 && bullet.getX() >= Math.min(x1, x2) && bullet.getX() <= Math.max(x1, x2) && bullet.getY() >= Math.min(y1, y2) && bullet.getY() <= Math.max(y1, y2)){
            bullet.setLife(false);
            return false;
        }
        if(myTank.isLife() && bullet.getX() >= myTank.getX() && bullet.getY() >= myTank.getY() && bullet.getX() <= myTank.getX() + (myTank.getDir() % 2 < 1 ? 30 : 45) && bullet.getY() <= myTank.getY() + (myTank.getDir() % 2 < 1 ? 45 : 30)){
            bullet.setLife(false);
            if(t1 < 1){
                sw ++;
                myTank.setLife(false);
                fh = 100;
            }
            return true;
        }
        for(EnemyTank enemy : enemyTanks){
            if(!bullet.isLife()) continue;
            if(bullet.getX() >= enemy.getX() && bullet.getY() >= enemy.getY() && bullet.getX() <= enemy.getX() + (enemy.getDir() % 2 < 1 ? 30 : 45) && bullet.getY() <= enemy.getY() + (enemy.getDir() % 2 < 1 ? 45 : 30)){
                bullet.setLife(false);
                enemy.setLife(false);
                return true;
            }
        }
        return false;
    }

    public boolean checkT(EnemyTank enemy){
        if(t3 < 1) return false;
        switch (enemy.getDir()){
            case 0:
            case 2:
                if(enemy.getX() > Math.min(x1, x2) - 30 && enemy.getX() < Math.max(x1, x2) && enemy.getY() > Math.min(y1, y2) - 45 && enemy.getY() < Math.max(y1, y2)){
                    enemy.setLife(false);
                    return true;
                }
                break;
            default:
                if(enemy.getX() > Math.min(x1, x2) - 45 && enemy.getX() < Math.max(x1, x2) && enemy.getY() > Math.min(y1, y2) - 30 && enemy.getY() < Math.max(y1, y2)){
                    enemy.setLife(false);
                    return true;
                }
        }
        return false;
    }
}
